/*
 * File:   RoutePlanner.cpp
 * Author: Thomas Trojer
 *
 * Created on 12. Juli 2010, 21:50
 */

/*
 routplanner gets fed with all rules
 then turtle gets initial food
 then turtle walks and tells routeplanner its motion/state (single tokens)
 finally routeplanner knows new route to be eaten by the turtle
 */

#include "turtle/RoutePlanner.h"

RoutePlanner::RoutePlanner() {}

RoutePlanner::~RoutePlanner() {}

/*
 receives every token the turtle formerly analyzed
 uses the rule applicable and appends to next temp string meal for the turtle
 if no rule is applicable token is left as is
 */
string RoutePlanner::plan(char token, float parameter[], int size) {
    /*printf("token is %c ( ", token);
    for(int i = 0; parameter && i < size; i++) {
        printf("%f ", parameter[i]);
    }
    printf(")\n");*/

    if(rules.count(token) > 0) {
        RuleList next = rules[token];

        for(RuleList::iterator iter = next.begin(); iter != next.end(); iter++) {
            Rule curRule = *iter;

            string curCondDup = string(curRule.condition);
            replaceVars(curCondDup, parameter, size);
            if(eval(curCondDup)) {
                string curBodyDup = string(curRule.body);
                replaceVars(curBodyDup, parameter, size);

                return curBodyDup;
            }
        }
    }

    return string();
}

string RoutePlanner::duplicate(char token, float parameter[], int size) {
    string dup = string(1, token);
    if(parameter && size > 0) {
        dup += "(";
        for(int i = 0; parameter && i < size; i++) {
            ostringstream flout;
            flout << parameter[i];
            dup += flout.str() + ",";
        }
        dup.replace(dup.length()-1, 1, ")");
    }

    return dup;
}

void RoutePlanner::rule(string arule) {
    string trule;
    for(int i = 0; i < arule.length(); i++) {
        if(arule[i] != ' ') {
            trule += arule[i];
        }
    }

    int impl_pos = trule.find("->");
    if(impl_pos == string::npos) {
        printf("Rule head to tail implication missing\n");
        return;
    }
    string head = trule.substr(0, impl_pos);

    Rule theRule;

    string tail = trule.substr(impl_pos+2);
    int cond_pos = tail.find(':');
    if(cond_pos == string::npos) {
        theRule.body = tail;
        theRule.condition = "true";
    } else {
        string condition = tail.substr(0, cond_pos);
        tail = tail.substr(cond_pos+1);

        theRule.body = tail;
        theRule.condition = condition;
    }

    rules[head[0]].push_back(theRule);
}

 void RoutePlanner::define(Define def) {
     defines.push_back(def);
 }

 void RoutePlanner::ignore(string var) {
     ignores.push_back(var);
 }

 void RoutePlanner::prepare(string &meal) {
     list<string>::iterator iter;
     for(iter = ignores.begin(); iter != ignores.end(); iter++) {
        int pos = meal.find(*iter);
        if(pos != std::string::npos) {
            meal.erase(pos, iter->length());
        }
    }
 }

void RoutePlanner::rule(char token, Rule theRule) {
    rules[token].push_back(theRule);
}

void RoutePlanner::trimString(string str) {
    int pos;
    while((pos = str.find(' ')) != string::npos) {
        str.erase(pos, 1);
    }
}

void RoutePlanner::replaceVars(string &str, float parameter[], int size) {
    if(size <= 0) {
        return;
    }

    int pos;
    std::srand((unsigned)std::time(0));
    float randnum = (float)std::rand() / RAND_MAX;

    while((pos = str.find('$')) != string::npos) {
        ostringstream numout;

        char cvar = str[pos+1];
        if(cvar == 'r' || cvar == 'R') {
            numout << randnum;
        } else {
            int var = (int)(str[pos+1]-48)-1; // ASCII to 1-digit int
            numout << parameter[var];
        }

        str.erase(pos, 2);
        str.insert(pos, numout.str());
    }
}
